package org.googlecode.viewt.core.tools.ejb;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.googlecode.viewt.core.tools.LogicDescRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class EJBGenerateCommand {
	private static Logger logger = LoggerFactory.getLogger(EJBGenerateCommand.class);
	
	
	public static final String OPT_INTERFACE_FILE = "blint";
	public static final String OPT_IMPLEMENT_FILE = "blimp";
	public static final String OPT_SOURCE_FILESET = "fileset";
	public static final String OPT_SERVICE_NAME = "bs";
	public static final String OPT_INCLUDE_METHODS = "incl";
	public static final String OPT_EXCLUDE_METHODS = "excl";
	public static final String OPT_PREFIX_PACKAGE = "prepack";
	public static final String OPT_PROJECT_NAME = "prj";
	public static final String OPT_MODULE_NAME = "mod";
	public static final String OPT_API_DEST = "api";
	public static final String OPT_IMP_DEST = "imp";
	public static final String OPT_CFG_DEST = "cfg";
	public static final String OPT_COPYRIGHT = "copyright";
	public static final String OPT_AUTHOR = "author";
	private String blintFile = null;

	private String blimpFile = null;

	private String[] srcFileSets = null;

	private String bsName = null;

	private String[] incMethods = null;

	private String[] excMethods = null;

	private String prePackName = "com.leadron";

	private String projectName = null;

	private String moduleName = null;

	private String apiDestPath = null;

	private String impDestPath = null;

	private String cfgDestPath = null;

	private String copyright = null;

	private String author = null;

	private LogicDescRepository logicRepository = new LogicDescRepository();

	public void parseArgs(String[] args) throws ParseException {
		
		CommandLineParser parser = new GnuParser();
		OptionBuilder.hasArg();
		OptionBuilder.isRequired();
		OptionBuilder
				.withDescription("interface source file of business logic");
		OptionBuilder.hasArg();
		OptionBuilder.isRequired();
		OptionBuilder
				.withDescription("implement source file of business logic");
		OptionBuilder.hasArg();
		OptionBuilder.hasArgs();
		OptionBuilder.withDescription("java source file sets");
		OptionBuilder.hasArg();
		OptionBuilder.isRequired();
		OptionBuilder.withDescription("business service name");
		OptionBuilder.hasArg();
		OptionBuilder.hasArgs();
		OptionBuilder
				.withDescription("methods to be wrapped into business service");
		OptionBuilder.hasArg();
		OptionBuilder.hasArgs();
		OptionBuilder
				.withDescription("methods not wrapped into business service");
		OptionBuilder.hasArg();
		OptionBuilder.withDescription("prefix of package name");
		OptionBuilder.hasArg();
		OptionBuilder.isRequired();
		OptionBuilder.withDescription("project name");
		OptionBuilder.hasArg();
		OptionBuilder.isRequired();
		OptionBuilder.withDescription("module name");
		OptionBuilder.hasArg();
		OptionBuilder.isRequired();
		OptionBuilder
				.withDescription("path to output implementation class file");
		OptionBuilder.hasArg();
		OptionBuilder.isRequired();
		OptionBuilder.withDescription("path to output API class file");
		OptionBuilder.hasArg();
		OptionBuilder.isRequired();
		OptionBuilder.withDescription("path to output config file");
		OptionBuilder.hasArg();
		OptionBuilder
				.withDescription("copyright information for generated code");
		OptionBuilder.hasArg();
		OptionBuilder.withDescription("author information for generated code");
		Options options = new Options()
				.addOption(OptionBuilder.create("blint")).addOption(
						OptionBuilder.create("blimp")).addOption(
						OptionBuilder.create("fileset")).addOption(
						OptionBuilder.create("bs")).addOption(
						OptionBuilder.create("incl")).addOption(
						OptionBuilder.create("excl")).addOption(
						OptionBuilder.create("prepack")).addOption(
						OptionBuilder.create("prj")).addOption(
						OptionBuilder.create("mod")).addOption(
						OptionBuilder.create("imp")).addOption(
						OptionBuilder.create("api")).addOption(
						OptionBuilder.create("cfg")).addOption(
						OptionBuilder.create("copyright")).addOption(
						OptionBuilder.create("author"));

		CommandLine cmdLine = parser.parse(options, args);

		this.blintFile = cmdLine.getOptionValue("blint");
		this.blimpFile = cmdLine.getOptionValue("blimp");
		this.srcFileSets = cmdLine.getOptionValues("fileset");
		this.bsName = cmdLine.getOptionValue("bs");
		this.incMethods = cmdLine.getOptionValues("incl");
		this.excMethods = cmdLine.getOptionValues("excl");
		this.projectName = cmdLine.getOptionValue("prj");
		this.moduleName = cmdLine.getOptionValue("mod");
		this.impDestPath = cmdLine.getOptionValue("imp");
		this.apiDestPath = cmdLine.getOptionValue("api");
		this.cfgDestPath = cmdLine.getOptionValue("cfg");

		if (cmdLine.hasOption("prepack"))
			this.prePackName = cmdLine.getOptionValue("prepack");
		if (cmdLine.hasOption("copyright"))
			this.copyright = cmdLine.getOptionValue("copyright");
		if (cmdLine.hasOption("author")) {
			this.author = cmdLine.getOptionValue("author");
		}

		System.out.println("Business logic interface:\t" + this.blintFile);
		System.out.println("Business logic implement:\t" + this.blimpFile);
		
		int i;
		if (this.srcFileSets != null) {
			System.out.println("Source file sets:");
			for (i = 0; i < this.srcFileSets.length; ++i)
				System.out.println("\t" + this.srcFileSets[i]);
		}
		System.out.println("Business service name to wrap:\t" + this.bsName);
		if (this.incMethods != null) {
			System.out.println("Include methods:");
			for (i = 0; i < this.incMethods.length; ++i)
				System.out.println("\t" + this.incMethods[i]);
		}
		if (this.excMethods != null) {
			System.out.println("Exclude methods:");
			for (i = 0; i < this.excMethods.length; ++i)
				System.out.println("\t" + this.excMethods[i]);
		}
		System.out.println("Package prefix:\t" + this.prePackName);
		System.out.println("Project name:\t" + this.projectName);
		System.out.println("Module name:\t" + this.moduleName);
		System.out.println("Implement output path:\t" + this.impDestPath);
		System.out.println("API output path:\t" + this.apiDestPath);
		System.out.println("Config output path:\t" + this.cfgDestPath);
	}

	public void parseSource() throws Exception {
		logger.debug("Begin parse business logic source");

		if (this.srcFileSets != null) {
			for (int i = 0; i < this.srcFileSets.length; ++i) {
				logger.debug("Parse source set of:" + this.srcFileSets[i]);
				this.logicRepository.addBLClass(this.srcFileSets[i]);
			}

		}

		this.logicRepository.setBLFile(this.blintFile, this.blimpFile);

		logger.debug("End parse business logic source");
	}

	public void performGen() throws Exception {
		BaseEJBGenerator generator = null;

		logger.debug("Begin generate local EJB home");
		generator = new LocalHomeGenerator();
		generator.setCopyright(this.copyright);
		generator.setAuthor(this.author);
		generator.setServiceName(this.bsName);
		generator.setPrePackName(this.prePackName);
		generator.setProjectName(this.projectName);
		generator.setModuleName(this.moduleName);
		generator.setDestPath(this.apiDestPath);
		generator.init(this.logicRepository, this.incMethods, this.excMethods);
		generator.performGen();
		logger.debug("End generate local EJB home");

		logger.debug("Begin generate local EJB interface");
		generator = new LocalInterfaceGenerator();
		generator.setCopyright(this.copyright);
		generator.setAuthor(this.author);
		generator.setServiceName(this.bsName);
		generator.setPrePackName(this.prePackName);
		generator.setProjectName(this.projectName);
		generator.setModuleName(this.moduleName);
		generator.setDestPath(this.apiDestPath);
		generator.init(this.logicRepository, this.incMethods, this.excMethods);
		generator.performGen();
		logger.debug("End generate local EJB interface");

		logger.debug("Begin generate remote EJB home");
		generator = new RemoteHomeGenerator();
		generator.setCopyright(this.copyright);
		generator.setAuthor(this.author);
		generator.setServiceName(this.bsName);
		generator.setPrePackName(this.prePackName);
		generator.setProjectName(this.projectName);
		generator.setModuleName(this.moduleName);
		generator.setDestPath(this.apiDestPath);
		generator.init(this.logicRepository, this.incMethods, this.excMethods);
		generator.performGen();
		logger.debug("End generate remote EJB home");

		logger.debug("Begin generate remote EJB interface");
		generator = new RemoteInterfaceGenerator();
		generator.setCopyright(this.copyright);
		generator.setAuthor(this.author);
		generator.setServiceName(this.bsName);
		generator.setPrePackName(this.prePackName);
		generator.setProjectName(this.projectName);
		generator.setModuleName(this.moduleName);
		generator.setDestPath(this.apiDestPath);
		generator.init(this.logicRepository, this.incMethods, this.excMethods);
		generator.performGen();
		logger.debug("End generate remote EJB interface");

		logger.debug("Begin generate EJB implementation");
		generator = new EJBImplementGenerator();
		generator.setCopyright(this.copyright);
		generator.setAuthor(this.author);
		generator.setServiceName(this.bsName);
		generator.setPrePackName(this.prePackName);
		generator.setProjectName(this.projectName);
		generator.setModuleName(this.moduleName);
		generator.setDestPath(this.impDestPath);
		generator.init(this.logicRepository, this.incMethods, this.excMethods);
		generator.performGen();
		logger.debug("End generate EJB implementation");

		logger.debug("Begin generate client business interface");
		generator = new BusinessInterfaceGenerator();
		generator.setCopyright(this.copyright);
		generator.setAuthor(this.author);
		generator.setServiceName(this.bsName);
		generator.setPrePackName(this.prePackName);
		generator.setProjectName(this.projectName);
		generator.setModuleName(this.moduleName);
		generator.setDestPath(this.impDestPath);
		generator.init(this.logicRepository, this.incMethods, this.excMethods);
		generator.performGen();
		logger.debug("End generate client business interface");

		logger.debug("Begin generate client helper");
		generator = new ClientHelperGenerator();
		generator.setCopyright(this.copyright);
		generator.setAuthor(this.author);
		generator.setServiceName(this.bsName);
		generator.setPrePackName(this.prePackName);
		generator.setProjectName(this.projectName);
		generator.setModuleName(this.moduleName);
		generator.setDestPath(this.impDestPath);
		generator.init(this.logicRepository, this.incMethods, this.excMethods);
		generator.performGen();
		logger.debug("End generate client helper");

		logger.debug("Begin generate spring bean config");
		generator = new BeanConfigGenerator();
		generator.setCopyright(this.copyright);
		generator.setAuthor(this.author);
		generator.setServiceName(this.bsName);
		generator.setPrePackName(this.prePackName);
		generator.setProjectName(this.projectName);
		generator.setModuleName(this.moduleName);
		generator.setDestPath(this.cfgDestPath);
		generator.init(this.logicRepository, this.incMethods, this.excMethods);
		generator.performGen();
		logger.debug("End generate spring bean config");
	}

	public static void main(String[] args) {
		System.out
				.println("EJB service generator, Copyright (c) 2006-2008 Leadron Information Technoloy co.,Ltd.");
		try {
			EJBGenerateCommand command = new EJBGenerateCommand();
			command.parseArgs(args);
			command.parseSource();
			command.performGen();
		} catch (ParseException parseEx) {
			System.out.println("Invalid command line argument, check the doc");
			System.out.println(parseEx.getMessage());
			System.exit(-1);
		} catch (Exception ex) {
			System.out.println("Generate EJB service source file fail");
			ex.printStackTrace();
			System.exit(-1);
		}

		System.out.println("Generation done.");
	}
}